<?php
namespace Leaps\Database\Query\Grammars;
use Leaps\Database\Query\Builder;
class SqlServerGrammar extends Grammar
{

    /**
     * The keyword identifier wrapper format.
     *
     * @var string
     */
    protected $wrapper = '[%s]';

    /**
     * Compile a select query into SQL.
     *
     * @param \Leaps\Database\Query\Builder
     * @return string
     */
    public function compileSelect(Builder $query)
    {
        $components = $this->compileComponents ( $query );
        if ( $query->offset > 0 ) {
            return $this->compileAnsiOffset ( $query, $components );
        }
        return $this->concatenate ( $components );
    }

    /**
     * Compile the "select *" portion of the query.
     *
     * @param \Leaps\Database\Query\Builder $query
     * @param array $columns
     * @return string
     */
    protected function compileColumns(Builder $query, $columns)
    {
        if ( ! is_null ( $query->aggregate ) ) return;
        $select = $query->distinct ? 'select distinct ' : 'select ';
        if ( $query->limit > 0 and $query->offset <= 0 ) {
            $select .= 'top ' . $query->limit . ' ';
        }
        return $select . $this->columnize ( $columns );
    }

    /**
     * Create a full ANSI offset clause for the query.
     *
     * @param \Leaps\Database\Query\Builder $query
     * @param array $components
     * @return string
     */
    protected function compileAnsiOffset(Builder $query, $components)
    {
        if ( ! isset ( $components ['orders'] ) ) {
            $components ['orders'] = 'order by (select 0)';
        }
        $orderings = $components ['orders'];
        $components ['columns'] .= $this->compileOver ( $orderings );
        unset ( $components ['orders'] );
        $start = $query->offset + 1;
        $constraint = $this->compileRowConstraint ( $query );
        $sql = $this->concatenate ( $components );
        return $this->compileTableExpression ( $sql, $constraint );
    }

    /**
     * Compile the over statement for a table expression.
     *
     * @param string $orderings
     * @return string
     */
    protected function compileOver($orderings)
    {
        return ", row_number() over ({$orderings}) as row_num";
    }

    /**
     * Compile the limit / offset row constraint for a query.
     *
     * @param \Leaps\Database\Query\Builder $query
     * @return string
     */
    protected function compileRowConstraint($query)
    {
        $start = $query->offset + 1;
        if ( $query->limit > 0 ) {
            $finish = $query->offset + $query->limit;
            return "between {$start} and {$finish}";
        }
        return ">= {$start}";
    }

    /**
     * Compile a common table expression for a query.
     *
     * @param string $sql
     * @param string $constraint
     * @return string
     */
    protected function compileTableExpression($sql, $constraint)
    {
        return "select * from ({$sql}) as temp_table where row_num {$constraint}";
    }

    /**
     * Compile the "limit" portions of the query.
     *
     * @param \Leaps\Database\Query\Builder $query
     * @param int $limit
     * @return string
     */
    protected function compileLimit(Builder $query, $limit)
    {
        return '';
    }

    /**
     * Compile the "offset" portions of the query.
     *
     * @param \Leaps\Database\Query\Builder $query
     * @param int $offset
     * @return string
     */
    protected function compileOffset(Builder $query, $offset)
    {
        return '';
    }

    /**
     * Compile a truncate table statement into SQL.
     *
     * @param \Leaps\Database\Query\Builder $query
     * @return array
     */
    public function compileTruncate(Builder $query)
    {
        return array (
                'truncate table ' . $this->wrapTable ( $query->from ) => array ()
        );
    }

    /**
     * Get the format for database stored dates.
     *
     * @return string
     */
    public function getDateFormat()
    {
        return 'Y-m-d H:i:s.000';
    }
}